package com.ksd.log;


import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;


/**
 * @Author: carlo
 * @Description: 控制器日志切面
 * @DateTime: 2022/10/23 21:18
 */
@Aspect
@Slf4j
@Component
//@ConditionalOnProperty :日志开关，引入的项目中yml文件需要配置log.aspect.enable参数，havingValue表示值的设定，等于true表示开启。
//matchIfMissing等于false表示如果yml文件不配置log.aspect.enable参数，那么不开启; 等于true则表示如果不配置log.aspect.enable参数，那么也开启。
@ConditionalOnProperty(name = {"log.aspect.enable"}, havingValue = "true", matchIfMissing = true)
public class LogAspect {

    /**
     * @Pointcut: 定义切入点路径。
     */
    @Pointcut("execution(* com.ksd.*.controller.*Controller.*(..)) || execution(* com.ksd.*.service.*Service.*(..))")
    private void pointCut() {
    }



    /**
     *  Aspect 通知-通知的种类:
     *  Before advice： 前置通知，即在目标方法调用之前执行，注意：无论方法是否遇到异常都执行。
     *  After returning advice：后置通知，在目标方法执行后执行，前提是目标方法没有遇到异常，如果有异常则不执行通知。
     *  After throwing advice：异常通知，在目标方法抛出异常时执行，可以获取异常信息。
     *  After finally advice： 最终通知，在目标方法执行后执行，无论是否时异常执行。
     *  Around advice：环绕通知，最强大的通知类型，可以控制目标方法的执行，（通过调用ProceedingJoinPoint.proceed()）,可以在目标执行全过程中进行执行。
     */
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        Object[] reqArgs = pjp.getArgs();//获取请求参数
        String req = new Gson().toJson(reqArgs);
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();//获取方法签名对象
        //获取类名+方法名
        String methodName = methodSignature.getDeclaringType().getName() + "." + methodSignature.getName();
        log.info("{},reqParams:{}", methodName, req);
        Long startTime = System.currentTimeMillis();
        Object responseObj = pjp.proceed(); //方法执行
        String resp = new Gson().toJson(responseObj);//响应
        Long endTime = System.currentTimeMillis();
        log.info("{},response:{},costTime:{}", methodName, resp, endTime - startTime);
        return responseObj;
    }

}
